//
//  protocal.c
//  myvpn
//
//  Created by Zhuobin He on 12-12-31.
//  Copyright (c) 2012年 Zhuobin He. All rights reserved.
//


#include "SysLib.h"

#include "Protocal.h"
#include "Common.h"

int prime_num[] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
int prime_count = sizeof(prime_num) / sizeof(3);
PConfig CONFIG;


int parse_int16(char *buffer) {
    uint16_t plength;
    memcpy((void *)&plength, buffer, sizeof(plength));
    return (int16_t)ntohs(plength);

}

//tmp = struct.pack('>bhhb', s1, s2, packet_id, flag)

int decode_data(char *input_data, int input_size, PDecodedPacket output) {
    // Get length mark
//    unsigned char *input_data = (unsigned char *)tmp_data;
    int seed = input_data[0];
    int seed2 = parse_int16(input_data + 1);
    unsigned char *data_head = (unsigned char *)input_data + 3;

    int i;
    for (i = 0; i < 3; i++) {
        int tmp = (data_head[i] - i * seed - seed2) % 256;
        if (tmp < 0) tmp += 256;
        data_head[i] = (unsigned char)tmp;
    }

    output->pack_id = parse_int16(input_data + 3);
    output->flag = input_data[5];
    output->size = seed2 + seed;
    output->data[output->size] = 0;
    log_debug("id: %d, flag: %d, size: %d", output->pack_id, output->flag, output->size);
    if (output->size >= input_size - HEADER_SIZE) {
        log_error("Get illegal length mark %d", output->size);
        return 1;
    }

    data_head = (unsigned char *)input_data + HEADER_SIZE;
    unsigned char *output_data = (unsigned char *)output->data;
    for (i=0; i<output->size; i++) {
        int tmp = (data_head[i] - i * seed - seed2) % 256;
        if (tmp < 0) tmp += 256;
        output_data[i] = (unsigned char)tmp;
    }
    return 0;
}

void put_int16(char *buffer, int value) {
    uint16_t plength = htons((uint16_t)((int16_t)value));
    memcpy(buffer, (const char *)&plength, 2);
}

int encode_data(PDecodedPacket input, char *output_data, int *output_size) {
    int encoded_size = HEADER_SIZE + input->size;
    int padding = 0;
    if (encoded_size < CONFIG->min_packet) {
        padding = CONFIG->min_packet - encoded_size;
    }

    padding += random() % 16;

    int seed = prime_num[random() % prime_count];
    int seed2 = input->size - seed;
    output_data[0] = (unsigned char)seed;
    put_int16(output_data + 1, seed2);
    put_int16(output_data + 3, input->pack_id);
    output_data[5] = (unsigned char)input->flag;

    // Encode data
    unsigned char *data_header = (unsigned char *)output_data + 3;
    int i;
    for (i=0; i<3; i++) {
        data_header[i] = (unsigned char)((data_header[i] + i * seed + seed2) % 256);
    }
    data_header = (unsigned char *)output_data + HEADER_SIZE;
    for (i=0; i<input->size; i++) {
        data_header[i] = (unsigned char)((input->data[i] + i * seed + seed2) % 256);
    }

    for (i=0; i<3; i++) {
        input->data[i + 3] = (unsigned char)((input->data[i + 3] + i * seed + seed2) % 256);
    }

    // padding
    data_header = (unsigned char *)output_data + encoded_size;
    for (i=0; i<padding; i++) {
        data_header[i] = (unsigned char) random();
    }
    (*output_size) = encoded_size + padding;
    return 0;
}
